﻿using gbL.NetBoard.Helpers;
using gbL.NetBoard.Testing;
using NUnit.Framework;

namespace gbL.NetBoard.Tests
{
    [TestFixture]
    public class MessagesAdapterTests
    {
        [Test]
        public void Should_be_able_to_Accept_for_Added_only()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            int callsAccepted = 0;
            // A
            adapter.Accept<string>(x => { callsAccepted++; });
            adapter.EnableReceiver();
            blackboard.Add("hello");
            blackboard.Add(1);
            // A
            Assert.That(callsAccepted, Is.EqualTo(1));
        }

        [Test]
        public void Should_be_able_to_AcceptEntry_for_Added_only()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            int callsAccepted = 0;
            // A
            adapter.AcceptEntry<string>(x => { callsAccepted++; });
            adapter.EnableReceiver();
            blackboard.Add("hello");
            blackboard.Add(1);
            // A
            Assert.That(callsAccepted, Is.EqualTo(1));
        }

        [Test]
        public void Should_be_able_to_Accept_for_Added_and_Removed()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            int addedCalls = 0;
            int removedCalls = 0;
            // A
            adapter.Accept<string>(x => { addedCalls++; }, x => { removedCalls++; });
            adapter.EnableReceiver();
            var entry1 = blackboard.Add("hello");
            var entry2 = blackboard.Add(1);
            blackboard.TakeEntry(entry1);
            blackboard.TakeEntry(entry2);
            // A
            Assert.That(addedCalls, Is.EqualTo(1));
            Assert.That(removedCalls, Is.EqualTo(1));
        }

        [Test]
        public void Should_be_able_to_AcceptEntry_for_Added_and_Removed()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            int addedCalls = 0;
            int removedCalls = 0;
            // A
            adapter.AcceptEntry<string>(x => { addedCalls++; }, x => { removedCalls++; });
            adapter.EnableReceiver();
            var entry1 = blackboard.Add("hello");
            var entry2 = blackboard.Add(1);
            blackboard.TakeEntry(entry1);
            blackboard.TakeEntry(entry2);
            // A
            Assert.That(addedCalls, Is.EqualTo(1));
            Assert.That(removedCalls, Is.EqualTo(1));
        }

        [Test]
        public void Disposed_adapter_should_not_be_registered_with_blackboard()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            // A
            adapter.Dispose();
            // A
            Assert.That(blackboard.Broadcaster.GetInvocationListAdded(), Has.Length.EqualTo(0));
        }

        [Test]
        public void Disabled_adapter_should_not_receive_message_but_remain_registered_with_blackboard()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            int addedCount = 0;
            // A
            adapter.Accept<string>(x => { addedCount++; });
            adapter.EnableReceiver();
            blackboard.Add("hello");
            adapter.DisableReceiver();
            blackboard.Add("hello2");
            adapter.EnableReceiver();
            blackboard.Add("hello3");
            // A
            Assert.That(addedCount, Is.EqualTo(2));
        }

        [Test]
        public void Should_Send_message()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            // A
            adapter.Send("hello");
            // A
            Assert.That(blackboard.Read(), Has.Count.EqualTo(1));
        }

        [Test]
        public void Should_SendEntry_message()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            // A
            adapter.SendEntry("hello");
            // A
            Assert.That(blackboard.Read(), Has.Count.EqualTo(1));
        }

        public interface ISimpleMessageContract { string Value { get; set; } }

        public class SimpleMessageContract : ISimpleMessageContract { public string Value { get; set; } }

        [Test]
        public void Should_Accept_message_by_contract()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            int countAccepts = 0;
            adapter.Accept<ISimpleMessageContract>(x => { countAccepts++; });
            adapter.EnableReceiver();
            SimpleMessageContract message = new SimpleMessageContract() { Value = "hello" };
            // A
            blackboard.Add(message);
            // A
            Assert.That(countAccepts, Is.EqualTo(1));
        }

        [Test]
        public void Should_Send_message_by_contract()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            // A
            adapter.Send<ISimpleMessageContract>();
            // A
            Assert.That(blackboard.Read(), Has.Count.EqualTo(1));
            Assert.That(blackboard.Read()[0].Message, Is.InstanceOf<ISimpleMessageContract>());
        }

        [Test]
        public void Should_SendEntry_message_by_contract()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            // A
            adapter.SendEntry<ISimpleMessageContract>();
            // A
            Assert.That(blackboard.Read(), Has.Count.EqualTo(1));
            Assert.That(blackboard.Read()[0].Message, Is.InstanceOf<ISimpleMessageContract>());
        }

        [Test]
        public void Should_Send_and_initialise_message_by_contract()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            // A
            var sent = adapter.Send<ISimpleMessageContract>(x => x.Value = "hello");
            // A
            Assert.That(blackboard.Read(), Has.Count.EqualTo(1));
            Assert.That(sent.Value, Is.EqualTo("hello"));
        }

        [Test]
        public void Should_SendEntry_and_initialise_message_by_contract()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            // A
            var sent = adapter.SendEntry<ISimpleMessageContract>(x => x.Value = "hello");
            // A
            Assert.That(blackboard.Read(), Has.Count.EqualTo(1));
            Assert.That(((ISimpleMessageContract)sent.Message).Value, Is.EqualTo("hello"));
        }

        [Test]
        public void Should_LeaveMessage_on_blackboard_by_default()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter = new MessagesAdapter(blackboard);
            int acceptCount = 0;
            adapter.Accept<string>(x => { acceptCount++; });
            adapter.EnableReceiver();
            // A
            blackboard.Add("hello");
            // A
            Assert.That(acceptCount, Is.EqualTo(1));
            Assert.That(blackboard.Read(), Has.Count.EqualTo(1));
        }

        [Test]
        public void Should_Take_message_when_configured()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter1 = new MessagesAdapter(blackboard);
            MessagesAdapter adapter2 = new MessagesAdapter(blackboard);
            int acceptCount = 0;
            adapter1.Accept<string>(x => { acceptCount++; });
            adapter1.MessageBehaviour = ListenerMessageBehaviours.Take;
            adapter2.Accept<string>(x => { acceptCount++; });
            adapter2.MessageBehaviour = ListenerMessageBehaviours.Take;

            adapter1.EnableReceiver();
            adapter2.EnableReceiver();
            // A
            blackboard.Add("hello");
            // A
            Assert.That(acceptCount, Is.EqualTo(2));
            Assert.That(blackboard.Read(), Has.Count.EqualTo(0));
        }

        [Test]
        public void Should_require_and_take_message_when_configured_with_MustTake()
        {
            // A
            Blackboard blackboard = new Blackboard();
            MessagesAdapter adapter1 = new MessagesAdapter(blackboard);
            MessagesAdapter adapter2 = new MessagesAdapter(blackboard);
            int acceptCount = 0;
            adapter1.Accept<string>(x => { acceptCount++; });
            adapter1.MessageBehaviour = ListenerMessageBehaviours.MustTake;
            adapter2.Accept<string>(x => { acceptCount++; });
            adapter2.MessageBehaviour = ListenerMessageBehaviours.MustTake;

            adapter1.EnableReceiver();
            adapter2.EnableReceiver();
            // A
            blackboard.Add("hello");
            // A
            Assert.That(acceptCount, Is.EqualTo(1));
            Assert.That(blackboard.Read(), Has.Count.EqualTo(0));
        }
    }
}
